/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.openbookformat.chaptersviewer;

import java.beans.PropertyVetoException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Observable;
import java.util.logging.Logger;
import javax.swing.ActionMap;
import javax.swing.text.DefaultEditorKit;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ui.OpenProjects;
import org.openide.util.Exceptions;
import org.openide.util.LookupEvent;
import org.openide.util.NbBundle;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
import org.openide.util.ImageUtilities;
import org.netbeans.api.settings.ConvertAsProperties;
import org.openbookformat.project.BookProp;
import org.openbookformat.project.Chapter;
import org.openbookformat.project.ProjectUtil;
import org.openide.explorer.ExplorerManager;
import org.openide.explorer.ExplorerUtils;
import org.openide.explorer.view.ListView;
import org.openide.loaders.DataObject;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Node;
import org.openide.util.Lookup;
import org.openide.util.LookupListener;
import org.openide.util.Utilities;

/**
 * Top component which displays something.
 */
@ConvertAsProperties(dtd = "-//org.openbookformat.chaptersviewer//OBFChaptersViewer//EN",
autostore = false)
public final class OBFChaptersViewerTopComponent extends TopComponent implements ExplorerManager.Provider {

    private static OBFChaptersViewerTopComponent instance;
    /** path to the icon used by the component and its open action */
    static final String ICON_PATH = "org/openbookformat/chaptersviewer/book_open.png";
    private static final String PREFERRED_ID = "OBFChaptersViewerTopComponent";

    public OBFChaptersViewerTopComponent() {
        ActionMap map = this.getActionMap (); 
        map.put(DefaultEditorKit.copyAction, ExplorerUtils.actionCopy(manager)); 
        map.put(DefaultEditorKit.cutAction,ExplorerUtils.actionCut(manager)); 
        map.put(DefaultEditorKit.pasteAction, ExplorerUtils.actionPaste(manager));        
        associateLookup (ExplorerUtils.createLookup (manager, map));

        initComponents();
        setName(NbBundle.getMessage(OBFChaptersViewerTopComponent.class, "CTL_OBFChaptersViewerTopComponent"));
        setToolTipText(NbBundle.getMessage(OBFChaptersViewerTopComponent.class, "HINT_OBFChaptersViewerTopComponent"));
        setIcon(ImageUtilities.loadImage(ICON_PATH, true));
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        listPanel = new javax.swing.JPanel();
        jPanel1 = new javax.swing.JPanel();
        jMoveUp = new javax.swing.JButton();
        jMoveDown = new javax.swing.JButton();

        setLayout(new java.awt.BorderLayout());

        listPanel.setLayout(new java.awt.BorderLayout());
        add(listPanel, java.awt.BorderLayout.CENTER);
        view = new ListView();  listPanel.add(view);

        jPanel1.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));

        jMoveUp.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/openbookformat/chaptersviewer/bullet_arrow_up.png"))); // NOI18N
        org.openide.awt.Mnemonics.setLocalizedText(jMoveUp, org.openide.util.NbBundle.getMessage(OBFChaptersViewerTopComponent.class, "OBFChaptersViewerTopComponent.jMoveUp.text")); // NOI18N
        jMoveUp.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMoveUpActionPerformed(evt);
            }
        });
        jPanel1.add(jMoveUp);

        jMoveDown.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/openbookformat/chaptersviewer/bullet_arrow_down.png"))); // NOI18N
        org.openide.awt.Mnemonics.setLocalizedText(jMoveDown, org.openide.util.NbBundle.getMessage(OBFChaptersViewerTopComponent.class, "OBFChaptersViewerTopComponent.jMoveDown.text")); // NOI18N
        jMoveDown.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMoveDownActionPerformed(evt);
            }
        });
        jPanel1.add(jMoveDown);

        add(jPanel1, java.awt.BorderLayout.PAGE_END);
    }// </editor-fold>//GEN-END:initComponents

    private void jMoveUpActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMoveUpActionPerformed
        try {
            Node[] sNodes = manager.getSelectedNodes();
            if(sNodes.length == 0 || bookProp.indexOf(sNodes[0].
                    getLookup().lookup(Chapter.class)) == 0)
                return;

            Chapter chpt = null;
            int[] sIdx = new int[sNodes.length];
            for(int i = 0; i < sNodes.length; i++) {
                chpt =  sNodes[i].getLookup().lookup(Chapter.class);
                sIdx[i] = bookProp.moveChapterUp(chpt);
            }

            List<Node> nodes = new ArrayList(Arrays.asList( manager.getRootContext().getChildren().getNodes() ) );
            Node[] newSelNodes = new Node[sNodes.length];
            for(int i = 0; i < sIdx.length; i++) {
                newSelNodes[i] = nodes.get(sIdx[i]);
            }

            manager.setSelectedNodes(new Node[0]);
            manager.setSelectedNodes(newSelNodes);
            view.requestFocus();

        } catch (PropertyVetoException ex) {
            Exceptions.printStackTrace(ex);
        }
    }//GEN-LAST:event_jMoveUpActionPerformed

    private void jMoveDownActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMoveDownActionPerformed
        try {
            Node[] sNodes = manager.getSelectedNodes();
            System.out.println("sNodes.length:" + sNodes.length);
            System.out.println(bookProp.indexOf(sNodes[sNodes.length -1].
                    getLookup().lookup(Chapter.class)));
            System.out.println(bookProp.getTotalNumberOfChapter());
            if(sNodes.length == 0 || bookProp.indexOf(sNodes[sNodes.length -1].
                    getLookup().lookup(Chapter.class)) == bookProp.getTotalNumberOfChapter() -1)
                return;

            System.out.println("OK to move down..");
            Chapter chpt = null;
            int[] sIdx = new int[sNodes.length];
            for (int i = sNodes.length -1; i > -1; i--) {
                chpt = sNodes[i].getLookup().lookup(Chapter.class);
                sIdx[i] = bookProp.moveChapterDown(chpt);
            }

            List<Node> nodes = new ArrayList(Arrays.asList( manager.getRootContext().getChildren().getNodes() ) );
            Node[] newSelNodes = new Node[sNodes.length];
            for(int i = 0; i < sIdx.length; i++) {
                newSelNodes[i] = nodes.get(sIdx[i]);
            }

            manager.setSelectedNodes(new Node[0]);
            manager.setSelectedNodes(sNodes);
            view.requestFocus();
        } catch (PropertyVetoException ex) {
            Exceptions.printStackTrace(ex);
        }
    }//GEN-LAST:event_jMoveDownActionPerformed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton jMoveDown;
    private javax.swing.JButton jMoveUp;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel listPanel;
    // End of variables declaration//GEN-END:variables
    /**
     * Gets default instance. Do not use directly: reserved for *.settings files only,
     * i.e. deserialization routines; otherwise you could get a non-deserialized instance.
     * To obtain the singleton instance, use {@link #findInstance}.
     */
    public static synchronized OBFChaptersViewerTopComponent getDefault() {
        if (instance == null) {
            instance = new OBFChaptersViewerTopComponent();
        }
        return instance;
    }

    /**
     * Obtain the OBFChaptersViewerTopComponent instance. Never call {@link #getDefault} directly!
     */
    public static synchronized OBFChaptersViewerTopComponent findInstance() {
        TopComponent win = WindowManager.getDefault().findTopComponent(PREFERRED_ID);
        if (win == null) {
            Logger.getLogger(OBFChaptersViewerTopComponent.class.getName()).warning(
                    "Cannot find " + PREFERRED_ID + " component. It will not be located properly in the window system.");
            return getDefault();
        }
        if (win instanceof OBFChaptersViewerTopComponent) {
            return (OBFChaptersViewerTopComponent) win;
        }
        Logger.getLogger(OBFChaptersViewerTopComponent.class.getName()).warning(
                "There seem to be multiple components with the '" + PREFERRED_ID
                + "' ID. That is a potential source of errors and unexpected behavior.");
        return getDefault();
    }

    @Override
    public int getPersistenceType() {
        return TopComponent.PERSISTENCE_ALWAYS;
    }

    @Override
    public void componentOpened() {
        pResult = Utilities.actionsGlobalContext().lookupResult(Project.class);
        doResult = Utilities.actionsGlobalContext().lookupResult(DataObject.class);

        pResult.addLookupListener(new LookupListener() {
            @Override
            public void resultChanged(LookupEvent ev) {
                Collection c = ((Lookup.Result) ev.getSource()).allInstances();
                if(!c.isEmpty())
                    projectChanged((Project) c.iterator().next());
            }
        });

        doResult.addLookupListener(new LookupListener() {
            @Override
            public void resultChanged(LookupEvent ev) {
                Collection c = ((Lookup.Result) ev.getSource()).allInstances();
                if(!c.isEmpty())
                    projectChanged(FileOwnerQuery.getOwner(
                        ((DataObject) c.iterator().next()).getPrimaryFile()));
            }
        });

        projectChanged(OpenProjects.getDefault().getMainProject());
    }

    @Override
    public void componentClosed() {

    }

    private void projectChanged(Project nProject) {
        if(nProject == null || nProject == project)
            return;

        //remove old observer
        if (project != null)
            bookProp.getLookup().lookup(Observable.class)
                .deleteObserver(bookChildren);
        //switch project
        project = nProject;

        bookProp = project.getLookup().lookup(BookProp.class);
        bookChildren = new BookChildren(bookProp);
        if(bookChildren != null) {
            //add new observer
            bookProp.getLookup().lookup(Observable.class).
                    addObserver(bookChildren);
            manager.setRootContext(new AbstractNode(bookChildren));
        }
        ProjectUtil.getInstance().setProject(project);
    }

    void writeProperties(java.util.Properties p) {
        // better to version settings since initial version as advocated at
        // http://wiki.apidesign.org/wiki/PropertyFiles
        p.setProperty("version", "1.0");
        // TODO store your settings
    }

    Object readProperties(java.util.Properties p) {
        if (instance == null) {
            instance = this;
        }
        instance.readPropertiesImpl(p);
        return instance;
    }

    private void readPropertiesImpl(java.util.Properties p) {
        String version = p.getProperty("version");
        // TODO read your settings according to their version
    }

    @Override
    protected String preferredID() {
        return PREFERRED_ID;
    }

    @Override
    protected void componentActivated() {
        ExplorerUtils.activateActions(manager, true);
    }

    @Override
    protected void componentDeactivated() {
        ExplorerUtils.activateActions(manager, false);
    }


    @Override
    public ExplorerManager getExplorerManager() {
        return manager;
    }

    private ListView view;
    private Project project;
    private Lookup.Result pResult;
    private Lookup.Result doResult;
    private BookChildren bookChildren;
    private BookProp bookProp;
    private final ExplorerManager manager = new ExplorerManager();

}
